package com.geek.rest;

import com.geek.PathUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.reflect.MethodUtils;

import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.Produces;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;

import static com.geek.rest.RequestTemplate.SUPPORT_ANNOTATION_TYPES;


public class ReflectiveRequestTemplateResolver implements RequestTemplateResolver {
    /**
     * 解析 resourceClass 类的 resourceMethod 方法; 并将其解析成 RequestTemplate 类
     * @param resourceClass
     * @param resourceMethod
     * @return
     */
    @Override
    public RequestTemplate resolve(Class<?> resourceClass, Method resourceMethod) {
        String httpMethod = httpMethod(resourceMethod);
        String requestPath = requestPath(resourceClass, resourceMethod);
        String[] consumers = consumers(resourceClass, resourceMethod);
        String[] produces = produces(resourceClass, resourceMethod);
        List<AnnotatedParamMetadata> paramMetadata = annotatedParamMetada(resourceMethod);

        return new RequestTemplate()
                .method(httpMethod)
                .urlTemplate(requestPath)
                .consumers(consumers)
                .produces(produces)
                .annotatedParamMetadata(paramMetadata);
    }

    private List<AnnotatedParamMetadata> annotatedParamMetada(Method resourceMethod) {
        List<AnnotatedParamMetadata> metadataList = new LinkedList<>();

        Parameter[] parameters = resourceMethod.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];

            Annotation paramAnnotation = null;
            //一个参数只能有其中一个注解; 不可能存在多个注解
            for (Class<? extends Annotation> annotationType : SUPPORT_ANNOTATION_TYPES) {
                paramAnnotation = parameter.getAnnotation(annotationType);
                if (paramAnnotation != null) {
                    break;
                }
            }

            if (paramAnnotation == null) {
                continue;
            }
            String paramName = resolveParamName(paramAnnotation);
            String defaultValue = resolveDefaultValue(parameter);

            AnnotatedParamMetadata metadata = new AnnotatedParamMetadata();
            metadata.setAnnotationType(paramAnnotation.annotationType());
            metadata.setParameterIndex(i);
            metadata.setDefaultValue(defaultValue);
            metadata.setParamName(paramName);
            metadataList.add(metadata);
        }
        return metadataList;
    }

    private String resolveDefaultValue(Parameter parameter) {
        return Optional.ofNullable(parameter.getAnnotation(DefaultValue.class))
                .map(anno -> anno.value())
                .orElse(null);
    }


    private String resolveParamName(Annotation annotation) {
        try {
            return (String) MethodUtils.invokeMethod(annotation, "value", ArrayUtils.EMPTY_OBJECT_ARRAY);
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
    }


    /**
     * 方法可以覆盖类的设置
     * //todo 这里小马哥的是类上优先;写完代码有时间看下
     * @param resourceClass
     * @param resourceMethod
     */
    private String[] consumers(Class<?> resourceClass, Method resourceMethod) {
        Consumes methodAnnotation = resourceMethod.getAnnotation(Consumes.class);
        if (methodAnnotation != null) {
            return methodAnnotation.value();
        }
        Consumes classAnnotation = resourceClass.getAnnotation(Consumes.class);
        if (classAnnotation != null) {
            return classAnnotation.value();
        }
        return null;
    }

    private String[] produces(Class<?> resourceClass, Method resourceMethod) {
        Produces methodAnnotation = resourceMethod.getAnnotation(Produces.class);
        if (methodAnnotation != null) {
            return methodAnnotation.value();
        }
        Produces classAnnotation = resourceClass.getAnnotation(Produces.class);
        if (classAnnotation != null) {
            return classAnnotation.value();
        }
        return null;
    }

    /**
     * 获取请求路径; 请求路径为: 类上的Path + 方法上的Path
     * @param resourceClass
     * @param resourceMethod
     * @return
     */
    private String requestPath(Class<?> resourceClass, Method resourceMethod) {
        String classPath = PathUtils.resolvePath(resourceClass);
        String methodPath = PathUtils.resolvePath(resourceMethod);
        if (classPath != null) {
            return classPath + methodPath;
        }
        return methodPath;
    }

    /**
     * 获取请求方式
     * @param resourceMethod
     * @return
     */
    private String httpMethod(Method resourceMethod) {
        for (Annotation annotation : resourceMethod.getAnnotations()) {
            HttpMethod httpMethod = annotation.annotationType().getAnnotation(HttpMethod.class);
            if (httpMethod != null) {
                return httpMethod.value();
            }
        }
        return null;
    }



}
